#include <cmath>
#include "gmp.h"
#include "predicates.h"

int left_turn(const point& a, const point& b, const point& c)
{
    double left_turn = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);

    if (eps * (std::abs((b.x - a.x) * (c.y - a.y)) + std::abs((b.y - a.y) * (c.x - a.x))) < left_turn)
    {
        return 1;
    }

    if (-(eps * (std::abs((b.x - a.x) * (c.y - a.y)) + std::abs((b.y - a.y) * (c.x - a.x)))) > left_turn)
    {
        return -1;
    }

    return exact_left_turn(a, b, c);
}

int exact_left_turn(const point& a, const point& b, const point& c)
{
    mpq_t bx;
    mpq_init(bx);
    mpq_set_d(bx, b.x);
    //mpq_out_str(NULL, 10, bx);

    mpq_t ax;
    mpq_init(ax);
    mpq_set_d(ax, a.x);
    //mpq_out_str(NULL, 10, ax);

    mpq_t cy;
    mpq_init(cy);
    mpq_set_d(cy, c.y);
    //mpq_out_str(NULL, 10, cy);

    mpq_t ay;
    mpq_init(ay);
    mpq_set_d(ay, a.y);
    //mpq_out_str(NULL, 10, ay);

    mpq_t by;
    mpq_init(by);
    mpq_set_d(by, b.y);
    //mpq_out_str(NULL, 10, by);

    mpq_t cx;
    mpq_init(cx);
    mpq_set_d(cx, c.x);
    //mpq_out_str(NULL, 10, cx);

    mpq_t tmp1;
    mpq_init(tmp1);
    mpq_sub(tmp1, bx, ax);
    //mpq_out_str(NULL, 10, tmp1); tmp1 = b.x - a.x

    mpq_t tmp2;
    mpq_init(tmp2);
    mpq_sub(tmp2, cy, ay);
    //mpq_out_str(NULL, 10, tmp2); tmp2 = c.y - a.y

    mpq_t result;
    mpq_init(result);
    mpq_mul(result, tmp1, tmp2);
    //mpq_out_str(NULL, 10, result); result = (b.x - a.x) * (c.y - a.y)

    mpq_sub(tmp1, by, ay);
    //mpq_out_str(NULL, 10, tmp1); tmp1 = b.y - a.y
    mpq_sub(tmp2, cx, ax);
    //mpq_out_str(NULL, 10, tmp2); tmp2 = c.x - a.x
    mpq_mul(tmp1, tmp1, tmp2);
    //mpq_out_str(NULL, 10, tmp1); tmp1 = (b.y - a.y) * (c.x - a.x)
    mpq_sub(result, result, tmp1);//result = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)

    mpq_clear(ax); mpq_clear(bx); mpq_clear(cx); mpq_clear(ay); mpq_clear(by); mpq_clear(cy); mpq_clear(tmp1); mpq_clear(tmp2);
    
    int sign = mpq_sgn(result); mpq_clear(result);

    return sign;
}